"""
性能监控模块
提供实时性能监控、统计分析和报告生成
"""

import time
import threading
import os
from typing import Dict, Any, List, Optional
from collections import deque
import json
from pathlib import Path

# 尝试导入psutil，如果失败则使用模拟实现
try:
    import psutil
    PSUTIL_AVAILABLE = True
except ImportError:
    PSUTIL_AVAILABLE = False
    print("警告: psutil未安装，性能监控功能将受限")
    print("安装命令: pip install psutil")


class PerformanceMonitor:
    """性能监控器"""
    
    def __init__(self, max_history: int = 1000):
        """
        初始化性能监控器
        
        Args:
            max_history: 最大历史记录数量
        """
        self.max_history = max_history
        self.start_time = time.time()
        
        # 性能指标
        self.metrics = {
            'cpu_usage': deque(maxlen=max_history),
            'memory_usage': deque(maxlen=max_history),
            'memory_mb': deque(maxlen=max_history),
            'processing_rate': deque(maxlen=max_history),
            'api_response_time': deque(maxlen=max_history),
            'cache_hit_rate': deque(maxlen=max_history),
            'error_rate': deque(maxlen=max_history),
            'throughput': deque(maxlen=max_history)
        }
        
        # 统计数据
        self.stats = {
            'total_processed': 0,
            'total_failed': 0,
            'total_errors': 0,
            'total_cache_hits': 0,
            'total_requests': 0,
            'peak_memory_mb': 0,
            'peak_cpu_percent': 0,
            'avg_response_time': 0,
            'avg_throughput': 0
        }
        
        # 实时状态
        self.current_status = {
            'is_monitoring': False,
            'current_batch': 0,
            'total_batches': 0,
            'images_per_second': 0,
            'estimated_time_remaining': 0
        }
        
        # 线程安全
        self.metrics_lock = threading.Lock()
        self.stats_lock = threading.Lock()
        self.status_lock = threading.Lock()
        
        # 监控线程
        self.monitor_thread = None
        self.monitor_interval = 1.0  # 秒
        
        # 历史记录
        self.snapshots = []
        self.snapshot_interval = 10  # 每10秒保存一次快照
        self.last_snapshot_time = time.time()
    
    def start_monitoring(self):
        """开始性能监控"""
        with self.status_lock:
            if self.current_status['is_monitoring']:
                return
            
            self.current_status['is_monitoring'] = True
            self.monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True)
            self.monitor_thread.start()
            print("性能监控已启动")
    
    def stop_monitoring(self):
        """停止性能监控"""
        with self.status_lock:
            self.current_status['is_monitoring'] = False
        
        if self.monitor_thread:
            self.monitor_thread.join(timeout=2)
            print("性能监控已停止")
    
    def _monitor_loop(self):
        """监控循环"""
        while True:
            with self.status_lock:
                if not self.current_status['is_monitoring']:
                    break
            
            try:
                self._collect_metrics()
                self._update_stats()
                self._save_snapshot_if_needed()
                time.sleep(self.monitor_interval)
                
            except Exception as e:
                print(f"监控错误: {str(e)}")
                time.sleep(self.monitor_interval)
    
    def _collect_metrics(self):
        """收集性能指标"""
        try:
            if PSUTIL_AVAILABLE:
                # CPU使用率
                cpu_percent = psutil.cpu_percent(interval=0.1)
                
                # 内存使用
                memory = psutil.virtual_memory()
                memory_mb = memory.used / 1024 / 1024
                
                # 进程内存
                process = psutil.Process(os.getpid())
                process_memory_mb = process.memory_info().rss / 1024 / 1024
            else:
                # 模拟数据
                cpu_percent = 0.0
                memory_mb = 0.0
                process_memory_mb = 0.0
            
            with self.metrics_lock:
                self.metrics['cpu_usage'].append(cpu_percent)
                self.metrics['memory_usage'].append(0.0)  # 模拟内存使用率
                self.metrics['memory_mb'].append(process_memory_mb)
            
            # 更新峰值
            with self.stats_lock:
                self.stats['peak_memory_mb'] = max(self.stats['peak_memory_mb'], process_memory_mb)
                self.stats['peak_cpu_percent'] = max(self.stats['peak_cpu_percent'], cpu_percent)
                
        except Exception as e:
            print(f"收集指标错误: {str(e)}")
    
    def _update_stats(self):
        """更新统计数据"""
        with self.metrics_lock, self.stats_lock:
            # 计算平均值
            if self.metrics['api_response_time']:
                self.stats['avg_response_time'] = sum(self.metrics['api_response_time']) / len(self.metrics['api_response_time'])
            
            if self.metrics['throughput']:
                self.stats['avg_throughput'] = sum(self.metrics['throughput']) / len(self.metrics['throughput'])
            
            # 计算缓存命中率
            if self.stats['total_requests'] > 0:
                cache_hit_rate = self.stats['total_cache_hits'] / self.stats['total_requests']
                self.metrics['cache_hit_rate'].append(cache_hit_rate)
            
            # 计算错误率
            total_operations = self.stats['total_processed'] + self.stats['total_failed']
            if total_operations > 0:
                error_rate = self.stats['total_errors'] / total_operations
                self.metrics['error_rate'].append(error_rate)
    
    def _save_snapshot_if_needed(self):
        """如果需要，保存性能快照"""
        current_time = time.time()
        if current_time - self.last_snapshot_time >= self.snapshot_interval:
            self._save_snapshot()
            self.last_snapshot_time = current_time
    
    def _save_snapshot(self):
        """保存性能快照"""
        snapshot = {
            'timestamp': time.time(),
            'uptime': time.time() - self.start_time,
            'stats': self.stats.copy(),
            'current_metrics': {
                name: list(values)[-1] if values else 0 
                for name, values in self.metrics.items()
            }
        }
        
        self.snapshots.append(snapshot)
        
        # 限制快照数量
        if len(self.snapshots) > 100:
            self.snapshots.pop(0)
    
    def record_image_processed(self, processing_time: float, cache_hit: bool = False):
        """记录图片处理事件"""
        with self.stats_lock:
            self.stats['total_processed'] += 1
            if cache_hit:
                self.stats['total_cache_hits'] += 1
        
        with self.metrics_lock:
            self.metrics['processing_rate'].append(processing_time)
            if processing_time > 0:
                throughput = 1 / processing_time
                self.metrics['throughput'].append(throughput)
    
    def record_image_failed(self):
        """记录图片处理失败"""
        with self.stats_lock:
            self.stats['total_failed'] += 1
    
    def record_api_request(self, response_time: float, success: bool = True):
        """记录API请求"""
        with self.stats_lock:
            self.stats['total_requests'] += 1
            if not success:
                self.stats['total_errors'] += 1
        
        with self.metrics_lock:
            self.metrics['api_response_time'].append(response_time)
    
    def update_batch_progress(self, current_batch: int, total_batches: int):
        """更新批次进度"""
        with self.status_lock:
            self.current_status['current_batch'] = current_batch
            self.current_status['total_batches'] = total_batches
            
            # 估算剩余时间
            if current_batch > 0:
                elapsed_time = time.time() - self.start_time
                avg_time_per_batch = elapsed_time / current_batch
                remaining_batches = total_batches - current_batch
                self.current_status['estimated_time_remaining'] = avg_time_per_batch * remaining_batches
    
    def update_images_per_second(self, ips: float):
        """更新每秒处理图片数"""
        with self.status_lock:
            self.current_status['images_per_second'] = ips
        
        with self.metrics_lock:
            self.metrics['throughput'].append(ips)
    
    def get_current_metrics(self) -> Dict[str, Any]:
        """获取当前性能指标"""
        with self.metrics_lock, self.stats_lock, self.status_lock:
            return {
                'current': {
                    name: values[-1] if values else 0
                    for name, values in self.metrics.items()
                },
                'stats': self.stats.copy(),
                'status': self.current_status.copy(),
                'uptime': time.time() - self.start_time
            }
    
    def get_performance_summary(self) -> Dict[str, Any]:
        """获取性能摘要"""
        with self.metrics_lock, self.stats_lock:
            summary = {
                'uptime': time.time() - self.start_time,
                'total_processed': self.stats['total_processed'],
                'total_failed': self.stats['total_failed'],
                'success_rate': 0,
                'peak_memory_mb': self.stats['peak_memory_mb'],
                'peak_cpu_percent': self.stats['peak_cpu_percent'],
                'avg_response_time': self.stats['avg_response_time'],
                'avg_throughput': self.stats['avg_throughput'],
                'cache_hit_rate': 0,
                'error_rate': 0
            }
            
            # 计算成功率
            total = summary['total_processed'] + summary['total_failed']
            if total > 0:
                summary['success_rate'] = summary['total_processed'] / total
            
            # 计算缓存命中率
            if self.stats['total_requests'] > 0:
                summary['cache_hit_rate'] = self.stats['total_cache_hits'] / self.stats['total_requests']
            
            # 计算错误率
            if self.metrics['error_rate']:
                summary['error_rate'] = sum(self.metrics['error_rate']) / len(self.metrics['error_rate'])
            
            return summary
    
    def get_detailed_report(self) -> Dict[str, Any]:
        """获取详细性能报告"""
        with self.metrics_lock, self.stats_lock:
            report = {
                'summary': self.get_performance_summary(),
                'metrics_history': {
                    name: list(values) for name, values in self.metrics.items()
                },
                'snapshots': self.snapshots,
                'system_info': {
                    'cpu_count': psutil.cpu_count() if PSUTIL_AVAILABLE else 4,
                    'memory_total_gb': psutil.virtual_memory().total / 1024 / 1024 / 1024 if PSUTIL_AVAILABLE else 8.0,
                    'disk_usage_percent': psutil.disk_usage('.').percent if PSUTIL_AVAILABLE else 50.0
                }
            }
            return report
    
    def print_real_time_status(self):
        """打印实时状态"""
        metrics = self.get_current_metrics()
        
        print("\n" + "="*50)
        print("实时性能监控")
        print("="*50)
        print(f"运行时间: {metrics['uptime']:.1f}秒")
        print(f"CPU使用率: {metrics['current']['cpu_usage']:.1f}%")
        print(f"内存使用: {metrics['current']['memory_mb']:.1f}MB ({metrics['current']['memory_usage']:.1f}%)")
        print(f"处理速度: {metrics['status']['images_per_second']:.2f} 图片/秒")
        print(f"API响应时间: {metrics['current']['api_response_time']:.2f}秒")
        print(f"缓存命中率: {metrics['current']['cache_hit_rate']:.2%}")
        print(f"错误率: {metrics['current']['error_rate']:.2%}")
        
        if metrics['status']['total_batches'] > 0:
            progress = metrics['status']['current_batch'] / metrics['status']['total_batches']
            print(f"批次进度: {metrics['status']['current_batch']}/{metrics['status']['total_batches']} ({progress:.1%})")
            
            if metrics['status']['estimated_time_remaining'] > 0:
                remaining_min = metrics['status']['estimated_time_remaining'] / 60
                print(f"预计剩余时间: {remaining_min:.1f}分钟")
        
        print("="*50)
    
    def export_report(self, file_path: str):
        """导出性能报告到文件"""
        try:
            report = self.get_detailed_report()
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(report, f, indent=2, ensure_ascii=False)
            print(f"性能报告已导出到: {file_path}")
        except Exception as e:
            print(f"导出报告失败: {str(e)}")
    
    def reset_stats(self):
        """重置统计数据"""
        with self.stats_lock:
            for key in self.stats:
                if isinstance(self.stats[key], (int, float)):
                    self.stats[key] = 0
        
        with self.metrics_lock:
            for metric in self.metrics.values():
                metric.clear()
        
        self.snapshots.clear()
        self.start_time = time.time()
        print("性能统计已重置")


class PerformanceProfiler:
    """性能分析器"""
    
    def __init__(self):
        self.profiles = {}
        self.current_profile = None
        self.start_time = None
    
    def start_profile(self, name: str):
        """开始性能分析"""
        self.current_profile = name
        self.start_time = time.time()
        self.profiles[name] = {
            'start_time': self.start_time,
            'events': []
        }
    
    def record_event(self, event_name: str, data: Any = None):
        """记录事件"""
        if self.current_profile and self.current_profile in self.profiles:
            event = {
                'name': event_name,
                'timestamp': time.time() - self.start_time,
                'data': data
            }
            self.profiles[self.current_profile]['events'].append(event)
    
    def end_profile(self) -> Dict[str, Any]:
        """结束性能分析"""
        if not self.current_profile:
            return {}
        
        profile = self.profiles[self.current_profile]
        profile['end_time'] = time.time()
        profile['duration'] = profile['end_time'] - profile['start_time']
        
        result = profile.copy()
        self.current_profile = None
        self.start_time = None
        
        return result
    
    def get_profile_summary(self, name: str) -> Dict[str, Any]:
        """获取分析摘要"""
        if name not in self.profiles:
            return {}
        
        profile = self.profiles[name]
        events = profile.get('events', [])
        
        summary = {
            'name': name,
            'duration': profile.get('duration', 0),
            'event_count': len(events),
            'events': {}
        }
        
        # 按事件类型分组
        for event in events:
            event_name = event['name']
            if event_name not in summary['events']:
                summary['events'][event_name] = []
            summary['events'][event_name].append(event['timestamp'])
        
        # 计算统计
        for event_name, timestamps in summary['events'].items():
            summary['events'][event_name] = {
                'count': len(timestamps),
                'first': min(timestamps),
                'last': max(timestamps),
                'avg': sum(timestamps) / len(timestamps) if timestamps else 0
            }
        
        return summary